#pragma once
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <queue>
#include "task.hpp"

const int default_num = 5;

template <class T>
class BlockQueue
{
private:
    bool IsFull() { return _q.size() == _cap;}
    bool IsEmpty() { return _q.empty();}
public:
    BlockQueue(int cap = default_num)
        :_cap(cap),
        _csleep_num(0),
        _psleep_num(0)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_cond_p,nullptr);
        pthread_cond_init(&_cond_c,nullptr);
    }
    void Equeue(const T & in)
    {
        pthread_mutex_lock(&_mutex);
        {
            while(IsFull())
            {
                _psleep_num++;
                std::cout << "生产者休眠了" << std::endl;
                pthread_cond_wait(&_cond_p,&_mutex);
                _psleep_num--;
            }
            _q.push(in);
            if(_csleep_num > 0)
            {
                std::cout << "唤醒消费者"  << std::endl;
                pthread_cond_signal(&_cond_c);
            }
        }
        pthread_mutex_unlock(&_mutex);
    }

    T POP()
    {
        pthread_mutex_lock(&_mutex);
        {
            while(IsEmpty())
            {
                _csleep_num++;
                std::cout << "消费者休眠了" << std::endl;
                std::cout << std::endl;
                pthread_cond_wait(&_cond_c,&_mutex);
                _csleep_num--;
            }
            T data = _q.front();
            _q.pop();
            if(_psleep_num > 0)
            {
                std::cout << "唤醒生产者"  << std::endl;
                pthread_cond_signal(&_cond_p);
            }
            pthread_mutex_unlock(&_mutex);
            return data;
        }

    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond_p);
        pthread_cond_destroy(&_cond_c);
    }

private:
    pthread_mutex_t _mutex;
    pthread_cond_t _cond_c;
    pthread_cond_t _cond_p;
    std::queue<T> _q;

    int _csleep_num;
    int _psleep_num;

    int _cap;
};